#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""MEXICO data format

Copyright (c) 2011-2014 Christian T. Steigies <steigies@physik.uni-kiel.de>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

This module offers functions to read NM data from a PostgreSQL server
as used in Mexico and return data in the format as used by NMDB."""

__author__ = "Christian T. Steigies <steigies@physik.uni-kiel.de>"
__license__ = "GPL License"

from datetime import datetime, date

from nmdb.station.station_data import check_data, check_pressure
from nmdb.tools.datetool import str2date, str2time, str2datetime, valid_date
from nmdb.tools.configtool import parse_config

mexico_station = ["mxco"]

## --------------------------------------------------------------------------
def read_rt(options, station, data_type, year, month, day):
    """read realtime data

    options     verbose, dryrun, ...
    station     station short name, must be valid station
    data_type   "1m", "1h", "env", "meta"
    year        integer (1950-9999), may not be None
    month       integer (1-12), if None, read month 1-12
    day         integer (1-31), if None, read day 1-31

    return list of values in nmdb format
    """

    if station in mexico_station:
        pass
    else:
        raise ValueError  # wrong station

    value = []
    if valid_date(year, month, day):
        value = read_mxco(options, station, data_type, year, month, day)

    return value

## --------------------------------------------------------------------------
def read_rev(options, station, data_type, year, month, day):
    """read revised data

    options     verbose, dryrun, ...
    station     station short name, must be valid station
    data_type   "1m", "1h", "env", "meta"
    year        integer (1950-9999), may not be None
    month       integer (1-12), if None, read month 1-12
    day         integer (1-31), if None, read day 1-31

    return list of values in nmdb format
    """

    if station in mexico_station:
        pass
    else:
        raise ValueError  # wrong station

    value = []
    if valid_date(year, month, day):
        value = read_mxco(options, station, data_type, year, month, day)

    return value

## --------------------------------------------------------------------------
def read_mxco(options, station, data_type, year, month, day):
    """read data from Mexico PostgreSQL database"""

    try:
        import psycopg2
    except ImportError:
        print "psychopg2 not available: can not read mexico data"
        return None

    if station in mexico_station:
        (username, password, hostname) = parse_config(options.rcfile, "mexico", "orc")
    else:
        raise ValueError  # wrong station

    con = psycopg2.connect(host=hostname, database='orc', user=username, password=password) 
    cursor = con.cursor()

    if data_type in ["1h"]:
        value = read_1h(options, cursor, year, month, day)
    elif data_type in ["1m", "ori"]:
        value = read_1m(options, cursor, year, month, day)
    elif data_type in ["env", "meta"]:
        return None
    else:
        raise ValueError  # illegal data_type

    return value

## --------------------------------------------------------------------------
def interval(num, data):
    """
    determine length of the measurement interval for measurement num in data
    by calculating the difference between measurement num and the next
    in case num is the last value in data,
    assume that the diff to the previous value is the length of the measurement
    """

    if len(data) == 0:
        raise ValueError  # data too short to calculate interval

    if num+1 < len(data):        
        d1 = str2date(data[num][0])
        d2 = str2date(data[num+1][0])
        t1 = str2time(data[num][1])
        t2 = str2time(data[num+1][1])
    else:
        d1 = str2date(data[num-1][0])
        d2 = str2date(data[num][0])
        t1 = str2time(data[num-1][1])
        t2 = str2time(data[num][1])

    delta = (datetime.combine(d2, t2) - datetime.combine(d1, t1)).seconds
    # delta = 60 or 3600, check date > 2008-09-17 | 19:15:00?
    return delta

## --------------------------------------------------------------------------
def read_1m(options, cursor, year, month, day):
    """read one day 1min of data from Mexico PostgreSQL database"""

    try:
        mydate = date(year, month, day)
    except ValueError:
        return None

    columns = ("n.fecha, n.hora_minuto, n.neutrones, n.neutrones_corregidos, c.pres_mb")
    qstr = ("SELECT %s FROM neutrones_minuto n, dato_crudo c WHERE n.fecha = date '%s' "
        "AND n.fecha=c.fecha AND n.hora_minuto=c.hora_minuto "
        "ORDER BY n.hora_minuto ASC;" % (columns, mydate))

    data =  []
    if options.dryrun:
        print qstr
        return data
    else:
        cursor.execute(qstr)

    while True:
        line = cursor.fetchone()
        if line == None:
            break
        if options.verbose > 1:
            print line
        (mydate, mytime, uncorr, corr, press) = line
        mydatetime = datetime.combine(mydate, mytime)
        if options.verbose:
            print mydatetime, uncorr, corr, press

        # before   2008-09-17 | 19:00:00 5 min resolution
        # starting 2008-09-17 | 19:15:00 1 min resolution
        if mydatetime <= str2datetime("2008-09-17 19:00:00"):
            myinterval = 300
        else:
            myinterval = 60
        uncorr = round(float(10. * uncorr / myinterval), 3)
        press = round(float(press), 3)
        corr = round(float(10. * corr / myinterval), 3)
        # round to three digits after the decimal
        
        uncorr = check_data(uncorr, cr_min=10., cr_max=10000.)
        press = check_pressure(press, p_min=600., p_max=1100.)
        corr = check_data(corr, cr_min=10., cr_max=10000.)
        ceff = corr

        data.append([  # order as in NMDB
                    mydatetime, myinterval, uncorr, ceff, corr, press
                    ])

    return data

## --------------------------------------------------------------------------
def read_1h(options, cursor, year, month, day):
    """read one day 1hour of data from Mexico PostgreSQL database"""

    try:
        mydate = date(year, month, day)
    except ValueError:
        return None
    
    # http://www.postgresql.org/docs/9.2/static/functions-datetime.html
    columns = ("fecha, hora, neutrones, neutrones_corregidos, pres_mb")
    qstr = ("SELECT %s FROM neutrones_hora WHERE fecha = date '%s' ORDER BY hora ASC;" % (columns, mydate))
    #print qstr
    cursor.execute(qstr)

    data =  []
    myinterval = 3600  # hour values
    while True:
        line = cursor.fetchone()
        if line == None:
            break
        if options.verbose > 1:
            print line
        (mydate, mytime, uncorr, corr, press) = line
        mydatetime = datetime.combine(mydate, mytime)
        if options.verbose:
            print mydatetime, uncorr, corr, press
                
        uncorr = round(float(10. * uncorr / myinterval), 3)
        press = round(float(press), 3)
        corr = round(float(10. * corr / myinterval), 3)
        # round to three digits after the decimal
        
        uncorr = check_data(uncorr, cr_min=10., cr_max=10000.)
        press = check_pressure(press, p_min=600., p_max=1100.)
        corr = check_data(corr, cr_min=10., cr_max=10000.)
        ceff = corr

        data.append([  # order as in NMDB
                    mydatetime, myinterval, uncorr, ceff, corr, press
                    ])

    return data

## --------------------------------------------------------------------------
def main():
    import optparse
    parser = optparse.OptionParser("usage: %prog [options]")
    parser.add_option("-v", dest="verbose", default=0, action="count",
            help="increment output verbosity; may be specified multiple times")
    (options, args) = parser.parse_args()

    print "This is the mexico module."

    station = "mxco"
    data_type="1h"
    data_type="1m"
    year = 2014
    month = 1
    day = 1

    #data = read_rev(options, station, data_type, year, month, day)
    data = read_rt(options, station, data_type, year, month, day)
    for line in data:
        print line

## --------------------------------------------------------------------------
if __name__ == '__main__':
    main()
